package org.third.common.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.impl.client.CloseableHttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by Huailong Tang(Jason) on 2017/8/29.
 */
@Component
public class VaultAndKubeRequestUtil {

	private static final Logger logger = LoggerFactory.getLogger(VaultAndKubeRequestUtil.class);

	private static ObjectMapper objectMapper = new ObjectMapper();

	private static RestTemplate restTemplate;

	private static RestTemplate kubeRestTemplate;

	private RestTemplate restTemplateTimeOut = new RestTemplate(getClientHttpRequestFactory());

	private ClientHttpRequestFactory getClientHttpRequestFactory() {
		int timeout = 2000;
		HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
		CloseableHttpClient httpclient = HttpClientUtils.getCertificateIngnoredAndWithClientCertificateHttpClient(
				EnvUtils.getEtcdclientcertificatefile(), EnvUtils.getEtcdclientcertificatepwd());
		clientHttpRequestFactory.setConnectTimeout(timeout);
		clientHttpRequestFactory.setHttpClient(httpclient);
		return clientHttpRequestFactory;

	}

	public VaultAndKubeRequestUtil() throws Exception {

		CloseableHttpClient httpclient = HttpClientUtils.getCertificateIngnoredAndWithClientCertificateHttpClient(
				EnvUtils.getEtcdclientcertificatefile(), EnvUtils.getEtcdclientcertificatepwd());
		CloseableHttpClient httpClientKube = HttpClientUtils.getCertificateIngnoredHttpClient();
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
		HttpComponentsClientHttpRequestFactory requestFactoryKube = new HttpComponentsClientHttpRequestFactory();

		requestFactory.setHttpClient(httpclient);
		requestFactoryKube.setHttpClient(httpClientKube);

		restTemplate = new RestTemplate(requestFactory);
		restTemplate.setErrorHandler(new CustomResponseErrorHandler());

		kubeRestTemplate = new RestTemplate(requestFactoryKube);
		kubeRestTemplate.setErrorHandler(new CustomResponseErrorHandler());
	}

	public Map<String, String> genCAPolicyJson(String realm, boolean isDefault, String... roleId) {

		String path, capabilities = "";
		if (isDefault) {
			path = "\"itom/suite/" + roleId[0] + "/*\"";
			capabilities = " {\n  capabilities = [\"create\", \"read\", \"update\"]\n}";
		} else {
			path = "\"" + realm + "/issue/*\"";
			capabilities = " {\n  capabilities = [\"update\"]\n}";
		}

		String hclstr = "path " + path + capabilities;

		Map<String, String> resultEntity = new HashMap<>();
		resultEntity.put("rules", hclstr);
		return resultEntity;
	}

	public Map<String, String> genRealmPolicyHcl(List<String> realms) {
		String hclStr = "";
		for (String realm : realms) {
			String comment = String.format("//%s realm policy\n", realm);
			String path = String.format("path \"%s/issue/*\"", realm);
			String capabilities = " {\n  capabilities = [\"update\"]\n}\n\n";
			hclStr += comment + path + capabilities;
		}

		Map<String, String> resultEntity = new HashMap<>();
		resultEntity.put("rules", hclStr);
		return resultEntity;
	}

	public Map<String, String> genApprolePlilolicy(String roleId, String approle) {
		String path1 = "\"itom/suite/" + roleId + "/*\"";
		String path2 = "\"auth/approle/role/" + approle + "/role-id\"";
		String capabilities1 = " {\n  capabilities = [\"create\", \"read\", \"update\"]\n}";
		String capabilities2 = " {\n  capabilities = [\"read\"]\n}";

		String hclstr = "path " + path1 + capabilities1 + "\n" + "path " + path2 + capabilities2;

		Map<String, String> resultEntity = new HashMap<>();
		resultEntity.put("rules", hclstr);
		return resultEntity;

	}

	public <T, S, V> ResponseEntity callRequestToVault(HttpMethod method, String uri, String token, T body,
			Class<S> responseClass, V... uriVariables) {

		HttpEntity entity = new HttpBuilder().setHeader("X-Vault-Token", token).buildEntityWithBody(body);

		logger.info("request to vault uri {} header {},and body {}", uri, entity.getHeaders(), entity.getBody());

		ResponseEntity responseEntity = null;
		if (uriVariables == null) {
			responseEntity = restTemplate.exchange(uri, method, entity, responseClass);
		} else {
			responseEntity = restTemplate.exchange(uri, method, entity, responseClass, uriVariables);
		}

		logger.info("call vault response status code {}", responseEntity.getStatusCode());
		logger.info("call vault response status info {}", responseEntity.getStatusCodeValue());
		logger.info("call vault response message {}", responseEntity.getBody());

		return responseEntity;
	}

	public <T, S, V> ResponseEntity callRequestToKubePatch(String uri, String token, T body, Class<S> responseClass,
			V... uriVariables) {
		HttpEntity entity = new HttpBuilder().setHeader("accept", "application/json")
				.setHeader("Content-Type", "application/strategic-merge-patch+json")
				.setHeader("Authorization", "Bearer " + token).buildEntityWithBody(body);

		logger.info("request to kube uri {} header {},and body {}", uri, entity.getHeaders().toString(),
				entity.getBody().toString());
		ResponseEntity responseEntity = null;
		if (uriVariables == null) {
			responseEntity = kubeRestTemplate.exchange(uri, HttpMethod.PATCH, entity, responseClass);
		} else {
			responseEntity = kubeRestTemplate.exchange(uri, HttpMethod.PATCH, entity, responseClass, uriVariables);
		}

		logger.info("call kube response status code {}", responseEntity.getStatusCode());
		logger.info("call kube response status info {}", responseEntity.getStatusCodeValue());
		logger.info("call kube response message {}", responseEntity.getBody());

		return responseEntity;
	}

	public <T, S, V> ResponseEntity callRequestToKube(HttpMethod method, String uri, String token, T body,
			Class<S> responseClass, V... uriVariables) {
		HttpEntity entity = new HttpBuilder().setHeader("Content-Type", "application/json")
				.setHeader("Authorization", "Bearer " + token).buildEntityWithBody(body);

		logger.info("request to kube uri {} header {},and body {}", uri, entity.getHeaders(), entity.getBody());
		ResponseEntity responseEntity = null;
		if (uriVariables == null) {
			responseEntity = kubeRestTemplate.exchange(uri, method, entity, responseClass);
		} else {
			responseEntity = kubeRestTemplate.exchange(uri, method, entity, responseClass, uriVariables);
		}

		logger.info("call kube response status code {}", responseEntity.getStatusCode());
		logger.info("call kube response status info {}", responseEntity.getStatusCodeValue());
		logger.info("call kube response message {}", responseEntity.getBody());

		return responseEntity;
	}

	public <T, S, V> ResponseEntity callRequestToKubeByYaml(HttpMethod httpMethod, String uri, String token, T body,
			Class<S> responseClass, V... uriVariables) {
		HttpEntity entity = new HttpBuilder().setHeader("Content-Type", "application/yaml")
				.setHeader("Authorization", "Bearer " + token).buildEntityWithBody(body);

		logger.info("request to kube uri {} header {},and body {}", uri, entity.getHeaders(), entity.getBody());
		ResponseEntity responseEntity = null;
		if (uriVariables == null) {
			responseEntity = kubeRestTemplate.exchange(uri, httpMethod, entity, responseClass);
		} else {
			responseEntity = kubeRestTemplate.exchange(uri, httpMethod, entity, responseClass, uriVariables);
		}

		logger.info("call kube response status code {}", responseEntity.getStatusCode());
		logger.info("call kube response status info {}", responseEntity.getStatusCodeValue());
		logger.info("call kube response message {}", responseEntity.getBody());

		return responseEntity;
	}

	public ResponseEntity callRequestToSpecURL(HttpMethod httpMethod, String uri, Class reponseClass) {
		HttpEntity entity = new HttpBuilder().buildEntity();
		// HttpComponentsClientHttpRequestFactory rf =
		// (HttpComponentsClientHttpRequestFactory)
		// restTemplateTimeOut.getRequestFactory();
		// rf.setConnectTimeout(1 * 2000);
		restTemplateTimeOut.setErrorHandler(new CustomResponseErrorHandler());
		ResponseEntity responseEntity = restTemplateTimeOut.exchange(uri, httpMethod, entity, reponseClass);
		return responseEntity;
	}

	public boolean isAnyStringNullOrEmpty(String... strings) {
		for (String s : strings)
			if (s == null || s.isEmpty())
				return true;
		return false;
	}

	public boolean isAnyFileNullOrEmpty(MultipartFile... files) {
		for (MultipartFile file : files) {
			if (file == null || file.isEmpty()) {
				return true;
			}
		}
		return false;
	}

	public boolean isHttpSuccessful(HttpStatus httpStatus) {
		return (httpStatus.value() / 100 == 2);
	}

	public boolean isHttpFail(HttpStatus httpStatus) {
		return (httpStatus.value() / 100 != 2);
	}

	public String genKubeURL(String host, String port, String uri) {
		return "https://" + host + ":" + port + uri;
	}

	public String genKubeURLForHttp(String host, String port, String uri) {
		return "http://" + host + ":" + port + uri;
	}

}
